package task

import (
	"database/sql"
	"github.com/tsuna/gohbase"
	"EasyData/to-hbase"
	log "code.google.com/p/log4go"
	"EasyData/global"
	"EasyData/from"
	"EasyData/util"
	"sync"
	"time"
)
/**
	逻辑执行对象
 */
type UnitTask struct {
	DB       *sql.DB           //数据库连接
	hbase    gohbase.Client    // Hbase连接
	excustor to_hbase.Excustor //导切目的地执行器
	task     *global.Task      //任务配置
	Running  bool              //当前任务是否在执行
	lock     *sync.Mutex       //程序执行锁
	Pause    bool              //是否是暂停状态，如果状态是暂停，则逻辑不执行
}
/**
	逻辑执行单元，采用定时任务的方式启动
	如果task的isFlow配置为true，则只要能查询出数据，就会一直执行。
	如果是false，定时任务触发后只执行一次。
 */
func (t *UnitTask) cronRun(){
	if t.task.IsFlow {
		for {
			size := t.waitRun()
			if size == 0 {
				break
			}
		}
	}else{
		t.waitRun()
	}
}

/**
	逻辑执行单元，采用人工触发的方式,人工触发的方式，只要能查询出数据，就会一直执行
	直到查询不出数据为止，该此触发的任务则为完成
	返回该次查询出的数据的大小
 */
func (t *UnitTask) waitRun() (size int){
	if !t.Pause {
		if !t.Running && t.setRunning() {
			task := t.task
			db := t.DB
			results := from.FetchData(task, db)
			log.Info("taskName [%s] taskCommand [%s] Database [%s] Table [%s] resultsSzie [%v]",
				task.TaskName, task.TaskCommond, task.Database, task.Table, len(results))

			c := make(chan int)
			for v := range results {
				go t.excustor.TaskExcuse(results[v], c, db, task)
			}
			t.keepAlive(results, c)
			log.Info("taskName [%s] taskCommand [%s] excuseDown [%s]", task.TaskName, task.TaskCommond,
				util.GetCurrentTimeStr())

			time.Sleep(time.Duration(task.Speed)*time.Millisecond)
			defer t.setUnRunning()
			return len(results)
		}
	}
	return 0
}

/**
	保持主线程阻塞，所有逻辑执行完后放行
 */
func (t *UnitTask) keepAlive(results []map[string]interface{}, c chan int) {
	for range results{
		<- c
	}
}
/**
	对任务的一个描述
 */
func (t *UnitTask) describe(){

	task := t.task

	if task.OnlyDelete {
		log.Info("任务名称：[%s] 任务描述：[%s] 任务类型：从mysql 中导出数据，然后直接删除，不导入Hbase。task.OnlyDelete[%t]",task.TaskName,task.TaskCommond,task.OnlyDelete)
	}
	if !task.OnlyDelete && task.Delete {
		log.Info("任务名称：[%s] 任务描述：[%s] 任务类型：从mysql 中导出数据,成功导入Hbase后，删除Mysql中的数据，task.Delete[%t]",task.TaskName,task.TaskCommond,task.OnlyDelete)
	}
	if !task.OnlyDelete && !task.Delete {
		log.Info("任务名称：[%s] 任务描述：[%s] 任务类型：从mysql 中导出数据,成功导入Hbase后，不删除Mysql中的数据，task.Delete[%t]",task.TaskName,task.TaskCommond,task.OnlyDelete)
	}

}
/**
	将未执行状态改为执行状态
	如果程序正在执行，更改则失败。利用互斥锁实现，仅对当前结构体的多次调用生效
 */
func (t *UnitTask) setRunning() (success bool ){
	t.lock.Lock()
	if t.Running {
		return false
	}
	t.Running =true
	defer t.lock.Unlock()
	return true
}
/**
	将正在执行的任务的状态改为未执行
 */
func (t *UnitTask) setUnRunning() {
	t.Running =false
}
